import pandas as pd
import numpy as np
import os
from datetime import datetime
import matplotlib.pyplot as plt
import seaborn as sns

def load_data(file_path='../data/room_occupancy.csv'):
    """
    加载房间占用数据集
    
    参数:
    file_path: 数据文件路径
    
    返回:
    DataFrame: 加载的数据
    """
    print(f"加载数据: {file_path}")
    # 检查文件是否存在
    if not os.path.exists(file_path):
        print(f"文件不存在: {file_path}")
        # 尝试寻找正确的路径
        current_dir = os.path.dirname(os.path.abspath(__file__))
        parent_dir = os.path.dirname(current_dir)
        alternative_path = os.path.join(parent_dir, 'data', 'room_occupancy.csv')
        print(f"尝试替代路径: {alternative_path}")
        if os.path.exists(alternative_path):
            file_path = alternative_path
        else:
            # 尝试加载处理后的数据
            processed_path = os.path.join(parent_dir, 'data', 'processed_room_occupancy.csv')
            if os.path.exists(processed_path):
                print(f"加载处理后的数据: {processed_path}")
                return pd.read_csv(processed_path)
            else:
                processed_path = os.path.join(parent_dir, 'data', 'first_clean', 'processed_room_occupancy.csv')
                if os.path.exists(processed_path):
                    print(f"加载处理后的数据: {processed_path}")
                    return pd.read_csv(processed_path)
                else:
                    raise FileNotFoundError(f"无法找到数据文件")
    
    # 加载数据
    df = pd.read_csv(file_path)
    print(f"成功加载数据，形状: {df.shape}")
    return df

def extract_time_features(df):
    """
    提取时间特征
    
    参数:
    df: 数据DataFrame
    
    返回:
    DataFrame: 添加时间特征后的数据
    """
    print("\n开始提取时间特征...")
    
    # 创建副本
    df_features = df.copy()
    
    # 检查是否已有DateTime列
    if 'DateTime' not in df_features.columns:
        if 'Date' in df_features.columns and 'Time' in df_features.columns:
            print("从Date和Time列创建DateTime列")
            # 合并日期和时间，注意日期格式
            df_features['DateTime'] = pd.to_datetime(
                df_features['Date'] + ' ' + df_features['Time'], 
                format='%d-%m-%Y %H:%M:%S', 
                dayfirst=True
            )
    
    # 确保DateTime列存在
    if 'DateTime' in df_features.columns:
        # 提取小时
        if 'Hour' not in df_features.columns:
            df_features['Hour'] = df_features['DateTime'].dt.hour
            print("已添加Hour特征")
        
        # 提取分钟
        if 'Minute' not in df_features.columns:
            df_features['Minute'] = df_features['DateTime'].dt.minute
            print("已添加Minute特征")
        
        # 提取星期几 (0=周一, 6=周日)
        if 'DayOfWeek' not in df_features.columns:
            df_features['DayOfWeek'] = df_features['DateTime'].dt.dayofweek
            print("已添加DayOfWeek特征")
        
        # 是否周末 (0=工作日, 1=周末)
        if 'IsWeekend' not in df_features.columns:
            df_features['IsWeekend'] = df_features['DayOfWeek'].isin([5, 6]).astype(int)
            print("已添加IsWeekend特征")
        
        # 提取一天中的时间段 (上午、下午、晚上、夜间) - 修改为数值编码
        if 'TimeOfDay' not in df_features.columns:
            hour = df_features['DateTime'].dt.hour
            # 将时间段编码为数值: 0=上午, 1=下午, 2=晚上, 3=夜间
            conditions = [
                (hour >= 5) & (hour < 12),
                (hour >= 12) & (hour < 18),
                (hour >= 18) & (hour < 22),
                (hour >= 22) | (hour < 5)
            ]
            time_of_day_values = [0, 1, 2, 3]  # 数值编码
            time_of_day_labels = ['Morning', 'Afternoon', 'Evening', 'Night']  # 对应的标签
            df_features['TimeOfDay'] = np.select(conditions, time_of_day_values, default=4)
            
            # 创建一个映射字典，用于可视化和解释
            time_of_day_mapping = {val: label for val, label in zip(time_of_day_values, time_of_day_labels)}
            print("已添加TimeOfDay特征 (数值编码: 0=上午, 1=下午, 2=晚上, 3=夜间)")
            print(f"TimeOfDay映射: {time_of_day_mapping}")
        
        # 提取是否工作时间 (9:00-18:00)
        if 'IsWorkingHour' not in df_features.columns:
            hour = df_features['DateTime'].dt.hour
            df_features['IsWorkingHour'] = ((hour >= 9) & (hour < 18)).astype(int)
            print("已添加IsWorkingHour特征")
    else:
        print("警告: 无法找到DateTime列或Date和Time列，跳过时间特征提取")
    
    # 可视化时间特征与占用人数的关系
    if 'Room_Occupancy_Count' in df_features.columns and 'Hour' in df_features.columns:
        plt.figure(figsize=(12, 6))
        hourly_occupancy = df_features.groupby('Hour')['Room_Occupancy_Count'].mean()
        hourly_occupancy.plot(kind='bar', color='skyblue')
        plt.title('Average Room Occupancy by Hour')
        plt.xlabel('Hour of Day')
        plt.ylabel('Average Occupancy')
        plt.grid(True, alpha=0.3)
        plt.tight_layout()
        
        # 确保输出目录存在
        output_dir = '../static/visualizations'
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)
        plt.savefig(os.path.join(output_dir, '时间特征_小时与占用人数.png'))
        plt.close()
    
    print("时间特征提取完成")
    return df_features

def calculate_sensor_statistics(df):
    """
    计算传感器数据的统计特征
    
    参数:
    df: 数据DataFrame
    
    返回:
    DataFrame: 添加传感器统计特征后的数据
    """
    print("\n开始计算传感器统计特征...")
    
    # 创建副本
    df_features = df.copy()
    
    # 温度传感器统计特征
    temp_cols = [col for col in df_features.columns if 'Temp' in col and col.startswith('S')]
    if temp_cols:
        # 计算均值
        if 'Temp_Mean' not in df_features.columns:
            df_features['Temp_Mean'] = df_features[temp_cols].mean(axis=1)
            print("已添加Temp_Mean特征")
        
        # 计算方差
        if 'Temp_Var' not in df_features.columns:
            df_features['Temp_Var'] = df_features[temp_cols].var(axis=1)
            print("已添加Temp_Var特征")
        
        # 计算最大值
        if 'Temp_Max' not in df_features.columns:
            df_features['Temp_Max'] = df_features[temp_cols].max(axis=1)
            print("已添加Temp_Max特征")
        
        # 计算最小值
        if 'Temp_Min' not in df_features.columns:
            df_features['Temp_Min'] = df_features[temp_cols].min(axis=1)
            print("已添加Temp_Min特征")
        
        # 计算温差 (最大值-最小值)
        if 'Temp_Range' not in df_features.columns:
            df_features['Temp_Range'] = df_features['Temp_Max'] - df_features['Temp_Min']
            print("已添加Temp_Range特征")
    
    # 光线传感器统计特征
    light_cols = [col for col in df_features.columns if 'Light' in col and col.startswith('S')]
    if light_cols:
        # 计算均值
        if 'Light_Mean' not in df_features.columns:
            df_features['Light_Mean'] = df_features[light_cols].mean(axis=1)
            print("已添加Light_Mean特征")
        
        # 计算方差
        if 'Light_Var' not in df_features.columns:
            df_features['Light_Var'] = df_features[light_cols].var(axis=1)
            print("已添加Light_Var特征")
        
        # 计算最大值
        if 'Light_Max' not in df_features.columns:
            df_features['Light_Max'] = df_features[light_cols].max(axis=1)
            print("已添加Light_Max特征")
        
        # 计算最小值
        if 'Light_Min' not in df_features.columns:
            df_features['Light_Min'] = df_features[light_cols].min(axis=1)
            print("已添加Light_Min特征")
    
    # 声音传感器统计特征
    sound_cols = [col for col in df_features.columns if 'Sound' in col and col.startswith('S')]
    if sound_cols:
        # 计算均值
        if 'Sound_Mean' not in df_features.columns:
            df_features['Sound_Mean'] = df_features[sound_cols].mean(axis=1)
            print("已添加Sound_Mean特征")
        
        # 计算方差
        if 'Sound_Var' not in df_features.columns:
            df_features['Sound_Var'] = df_features[sound_cols].var(axis=1)
            print("已添加Sound_Var特征")
        
        # 计算最大值
        if 'Sound_Max' not in df_features.columns:
            df_features['Sound_Max'] = df_features[sound_cols].max(axis=1)
            print("已添加Sound_Max特征")
    
    # PIR传感器统计特征
    pir_cols = [col for col in df_features.columns if 'PIR' in col and col.startswith('S')]
    if pir_cols:
        # 计算总和 (检测到运动的传感器数量)
        if 'PIR_Sum' not in df_features.columns:
            df_features['PIR_Sum'] = df_features[pir_cols].sum(axis=1)
            print("已添加PIR_Sum特征")
        
        # 计算是否有任何运动 (0=无运动, 1=有运动)
        if 'PIR_Any' not in df_features.columns:
            df_features['PIR_Any'] = (df_features[pir_cols].sum(axis=1) > 0).astype(int)
            print("已添加PIR_Any特征")
    
    # 可视化传感器统计特征与占用人数的关系
    if 'Room_Occupancy_Count' in df_features.columns:
        stat_features = []
        for feature in ['Temp_Mean', 'Light_Mean', 'Sound_Mean', 'PIR_Sum']:
            if feature in df_features.columns:
                stat_features.append(feature)
        
        if stat_features:
            plt.figure(figsize=(15, 10))
            for i, feature in enumerate(stat_features, 1):
                plt.subplot(2, 2, i)
                sns.boxplot(x='Room_Occupancy_Count', y=feature, data=df_features)
                plt.title(f'{feature} vs Room Occupancy')
                plt.xlabel('Number of People')
                plt.ylabel(feature)
                plt.grid(True, alpha=0.3)
            
            plt.tight_layout()
            
            # 确保输出目录存在
            output_dir = '../static/visualizations'
            if not os.path.exists(output_dir):
                os.makedirs(output_dir)
            plt.savefig(os.path.join(output_dir, '传感器统计特征与占用人数.png'))
            plt.close()
    
    print("传感器统计特征计算完成")
    return df_features

def create_interaction_features(df):
    """
    创建特征交互项
    
    参数:
    df: 数据DataFrame
    
    返回:
    DataFrame: 添加特征交互项后的数据
    """
    print("\n开始创建特征交互项...")
    
    # 创建副本
    df_features = df.copy()
    
    # 定义主要特征
    main_features = []
    for feature in ['Temp_Mean', 'Light_Mean', 'Sound_Mean', 'S5_CO2']:
        if feature in df_features.columns:
            main_features.append(feature)
    
    # 创建特征交互项
    if len(main_features) >= 2:
        for i in range(len(main_features)):
            for j in range(i+1, len(main_features)):
                feature1 = main_features[i]
                feature2 = main_features[j]
                interaction_name = f"{feature1}_x_{feature2}"
                
                if interaction_name not in df_features.columns:
                    df_features[interaction_name] = df_features[feature1] * df_features[feature2]
                    print(f"已添加{interaction_name}特征")
    
    print("特征交互项创建完成")
    return df_features

def feature_engineering_pipeline(input_path=None, output_path=None):
    """
    特征工程完整流程
    
    参数:
    input_path: 输入数据文件路径
    output_path: 输出数据文件路径
    
    返回:
    DataFrame: 添加特征后的数据
    """
    print("开始特征工程流程...")
    
    # 1. 加载数据
    # 如果input_path为None，则使用load_data的默认路径
    if input_path is None:
        df = load_data()
    else:
        df = load_data(input_path)
    
    # 2. 提取时间特征
    df = extract_time_features(df)
    
    # 3. 计算传感器统计特征
    df = calculate_sensor_statistics(df)
    
    # 4. 创建特征交互项
    df = create_interaction_features(df)
    
    # 5. 保存结果
    if output_path is None:
        output_dir = '../data/feature_engineering'
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)
        output_path = os.path.join(output_dir, 'room_occupancy_with_features.csv')
    
    # 确保输出目录存在
    output_dir = os.path.dirname(output_path)
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    
    df.to_csv(output_path, index=False)
    print(f"\n特征工程结果已保存至: {output_path}")
    print(f"数据形状: {df.shape}")
    print("新增特征列:")
    
    # 获取原始特征列表
    original_cols = ['Date', 'Time', 'S1_Temp', 'S2_Temp', 'S3_Temp', 'S4_Temp', 
                     'S1_Light', 'S2_Light', 'S3_Light', 'S4_Light', 
                     'S1_Sound', 'S2_Sound', 'S3_Sound', 'S4_Sound', 
                     'S5_CO2', 'S5_CO2_Slope', 'S6_PIR', 'S7_PIR', 'Room_Occupancy_Count']
    
    # 打印新增特征
    new_features = [col for col in df.columns if col not in original_cols]
    for feature in new_features:
        print(f"- {feature}")
    
    print("\n特征工程流程完成!")
    return df

def analyze_feature_importance(df):
    """
    分析特征重要性
    
    参数:
    df: 包含所有特征的DataFrame
    """
    if 'Room_Occupancy_Count' not in df.columns:
        print("错误: 数据中没有目标变量'Room_Occupancy_Count'")
        return
    
    print("\n分析特征与目标变量的相关性...")
    
    # 选择数值列
    numeric_cols = df.select_dtypes(include=['float64', 'int64']).columns
    numeric_cols = [col for col in numeric_cols if col != 'Room_Occupancy_Count']
    
    # 计算相关系数
    correlations = df[numeric_cols].corrwith(df['Room_Occupancy_Count']).abs().sort_values(ascending=False)
    
    print("\n特征与占用人数的相关性 (绝对值):")
    for feature, corr in correlations.items():
        print(f"{feature}: {corr:.4f}")
    
    # 可视化前15个最重要特征
    plt.figure(figsize=(12, 8))
    correlations.head(15).plot(kind='bar', color='skyblue')
    plt.title('Top 15 Features by Correlation with Room Occupancy')
    plt.xlabel('Features')
    plt.ylabel('Absolute Correlation')
    plt.xticks(rotation=45, ha='right')
    plt.grid(True, alpha=0.3)
    plt.tight_layout()
    
    # 确保输出目录存在
    output_dir = '../static/visualizations'
    if not os.path.exists(output_dir):
        os.makedirs(output_dir)
    plt.savefig(os.path.join(output_dir, '特征重要性_相关性.png'))
    plt.close()
    
    print("\n特征重要性分析完成")

if __name__ == "__main__":
    # 运行特征工程流程
    df_with_features = feature_engineering_pipeline()
    
    # 分析特征重要性
    analyze_feature_importance(df_with_features) 